gusucode.com > VC 点对点文件传输实例 > VC 点对点文件传输实例/code/www.NewXing.com/Server_FileTransfer/TCPServer_FT.cpp
// TCPServer_FT.cpp: implementation of the CTCPServer_FT class. ////////////////////////////////////////////////////////////////////// // Download by http://www.NewXing.com #include "stdafx.h" #include "TCPServer_FT.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// // Construction/Destruction//类的实现 ////////////////////////////////////////////////////////////////////// CTCPServer_FT::CTCPServer_FT() { } CTCPServer_FT::~CTCPServer_FT() { } //重载构造函数,添加参数:指向窗口的指针 CTCPServer_FT::CTCPServer_FT(LPVOID ptr) { m_iListenPort = 7000; m_bEndListenThread = TRUE;//停止监听 m_pWnd = (CWnd*)ptr; } //功能:设置监听端口 //参数:端口号 //返回:无 void CTCPServer_FT::SetListenPort(int iPort) { m_iListenPort = iPort; } //功能:开始监听客户端文件请求 //参数:指向接受消息的窗口的指针 //返回:无 void CTCPServer_FT::ListenRequest() { m_bEndListenThread = FALSE;//开始监听 DWORD id; HANDLE h = CreateThread(NULL, 0, ThreadListen, this, 0, &id);//创建句柄 //线程要执行的函数为ThreadListen,将this指针传递给线程,线程ID为id,创建成功,返回新线程的一个句柄 CloseHandle(h); //关闭句柄,并不终止线程 } //功能:停止监听 //参数:无 //返回:无 void CTCPServer_FT::StopListen() { m_bEndListenThread = TRUE; } //功能:监听线程 //参数:LPVOID lpParam //返回:无意义 DWORD WINAPI CTCPServer_FT::ThreadListen(LPVOID lpParam) { CTCPServer_FT* pServer = (CTCPServer_FT*)lpParam; SOCKET sockListen = socket(AF_INET, SOCK_STREAM, 0);//创建socket //地址家族为internet,用于TCP和UDP,字节流,特定的协议 SOCKADDR_IN sin; //转换地址 sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; //ip地址,以网路字节顺序。 sin.sin_port = htons(pServer->m_iListenPort); //端口号,从主机字节顺序转化成网络字节顺序 if(bind(sockListen, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR) {//若将socket与本地地址绑定失败 closesocket(sockListen); //关闭socket pServer->m_pWnd->SendMessage(WM_BINDERROR);//显示错误 return 1; } if(listen(sockListen, 5) == SOCKET_ERROR) {//若将socket置于监听失败 closesocket(sockListen); pServer->m_pWnd->SendMessage(WM_LISTENERROR); return 1; } //开始监听 pServer->m_pWnd->SendMessage(WM_STARTLISTEN); fd_set fdListen;//结构体,将socket放进一个集合 timeval seltime;//结构体,指定时间值(秒+毫秒) seltime.tv_sec = 0; //秒 seltime.tv_usec = 10000;//毫秒==10秒 while(!pServer->m_bEndListenThread) {//服务器在监听状态 FD_ZERO(&fdListen);//将集合清零 FD_SET(sockListen, &fdListen);//将socket添加到set中 if(select(0, &fdListen, NULL, NULL, &seltime) <= 0 || !FD_ISSET(sockListen, &fdListen) ) continue; //如果在规定时间内,set中无socket可读出||socket不在set中,结束本次循环,继续下次循环 int len = sizeof(sin); SOCKET sock = accept(sockListen, (SOCKADDR*)&sin, &len); //接受socket上的连接 PARAMRECV* pParamRecv = new PARAMRECV;//结构体,接收线程参数 pParamRecv->sock = sock; pParamRecv->ptr = pServer; DWORD id; HANDLE h = CreateThread(NULL, 0, ThreadRecv, pParamRecv, 0, &id); //创建ThreadRecv线程,将pParamRecv传递给线程 CloseHandle(h); } closesocket(sockListen); return 0; } //功能:接收线程 //参数:LPVOID lpParam //返回:无意义 DWORD WINAPI CTCPServer_FT::ThreadRecv(LPVOID lpParam) { PARAMRECV* pParam = (PARAMRECV*)lpParam;//指向接收线程的指针 CTCPServer_FT* pServer = (CTCPServer_FT*)pParam->ptr;//指向Server的指针 fd_set fdRecv;//结构体,接收线程集合 timeval seltime;//结构体,指定时间值==10s seltime.tv_sec = 0; seltime.tv_usec = 10000; while(1) { FD_ZERO(&fdRecv);//集合清零 FD_SET(pParam->sock, &fdRecv);//将已连接的socket加入集合 if(select(0, &fdRecv, NULL, NULL, &seltime) <= 0 || !FD_ISSET(pParam->sock, &fdRecv) ) continue; //如果在指定时间内,结构体内无可读接收线程||sock不在结构体内 MSGREQUEST msgRequest;//结构体,C--S通信缓冲区 int iRecvCnt = recv(pParam->sock, (char*)&msgRequest, sizeof(msgRequest), 0); //成功,返回接收字节数;正常结束,返回0;否则<0 if(iRecvCnt <= 0)//不成功 break;// 结束 //如果是请求文件列表 if(msgRequest.iCommand == FILELIST) { pServer->m_pWnd->SendMessage(WM_SENDFILELIST, (WPARAM)&pParam->sock, 0); //发送指定信息到窗口 } //如果是请求文件数据 else if(msgRequest.iCommand == FILEDATA) { long lFileOffset = msgRequest.lFileOffset;//文件偏移 CFile file; BOOL bResult = file.Open(msgRequest.sServerPath, CFile::modeRead|CFile::shareDenyNone, NULL); //打开指定路径的文件,只读||可共享,成功,返回非零;否则,0 if(!bResult) { break; //如果文件打开失败就终止线程 } char sSendBuf[SENDSIZE];//发送缓冲区,16K while(lFileOffset < msgRequest.lFileLength) {//当文件偏移<文件长度时 int iSeek = file.Seek(lFileOffset, CFile::begin);//寻找新的文件偏移,距离开始处 int iReadCnt = file.Read(sSendBuf, SENDSIZE);//读计数器,读到发送缓冲区,一次16K if(iReadCnt ==0)//读出字节数为0 break; int iSendCnt = send(pParam->sock, sSendBuf, iReadCnt, 0); //将读出的数据发送至已连接的socket,成功返回发送的字节数 //如果发送失败就终止线程 if(iSendCnt == -1) break; else lFileOffset += iSendCnt;//修改偏移量 }//end of while(lFileOffset < lFileLength) file.Close(); }//end of else if(msgRequest.iCommand == FILEDATA) break; }//end of while(1) closesocket(pParam->sock);//关闭socket delete pParam;//删除接收线程指针 return 0; }